package com.fly.code.process;

import java.io.File;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.xml.sax.InputSource;

import com.keta.generate.core.GenerateFactory;
import com.keta.generate.util.FreeMarkerUtil;
import com.keta.generate.util.Resources;
import com.keta.generate.util.StringUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * 代码生成进度条类
 *
 * @author 00fly
 * @version [版本号, 2017-4-4]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Slf4j
public class MybatisRunProgress implements IRunnableWithProgress
{
    private String driver;
    
    private String dburl;
    
    private String username;
    
    private String password;
    
    private String packName;
    
    String projectDir;
    
    private String projectSrcDir;
    
    private String[] tabName;
    
    String prefix;
    
    String codeType;
    
    // FreeMarker model
    Map<String, Object> model = new HashMap<String, Object>();
    
    public MybatisRunProgress(String driver, String dburl, String username, String password, String packName, String projectDir, String[] tabName, String prefix, String codeType)
    {
        super();
        this.driver = driver;
        this.dburl = dburl;
        this.username = username;
        this.password = password;
        this.packName = packName;
        this.projectDir = projectDir;
        this.projectSrcDir = projectDir + "src\\main\\java\\";
        this.tabName = tabName;
        this.prefix = prefix;
        this.codeType = codeType;
    }
    
    @Override
    public void run(IProgressMonitor monitor)
        throws InvocationTargetException, InterruptedException
    {
        // 在当前目录，创建并运行脚本
        try
        {
            monitor.beginTask("生成代码", IProgressMonitor.UNKNOWN);
            monitor.subTask("自动生成DAO、Map、MODEL 代码中......");
            creatAndRunMyBatis(driver, dburl, username, password, packName, projectSrcDir, tabName);
            monitor.done();
        }
        catch (Exception e)
        {
            log.error(e.getMessage());
            throw new InvocationTargetException(e.getCause(), e.getMessage());
        }
    }
    
    // 在当前目录，创建Mybatis 配置文件
    private String creatMybatisConig(String driver, String dburl, String username, String password, String packName, String projectSrcDir, String[] selection)
    {
        model.put("driver", driver);
        model.put("dburl", dburl);
        model.put("username", username);
        model.put("password", password);
        model.put("packName", packName);
        model.put("projectSrcDir", projectSrcDir);
        model.put("projectResourceDir", projectDir + "src\\main\\resources\\");
        model.put("tables", selection);
        new File(projectSrcDir).mkdirs();
        new File(projectDir + "src\\main\\resources\\").mkdirs();
        
        Map<String, String> domainName = new HashMap<>();
        for (String table : selection)
        {
            String domain = table;
            if (StringUtils.isNotBlank(prefix))
            {
                domain = table.replaceAll("(?i)^" + prefix, "");
            }
            domainName.put(table, StringUtil.camelCase(domain, true));
        }
        model.put("domains", domainName);
        model.put("date", new Date());
        return FreeMarkerUtil.renderMybatisConfig(model);
    }
    
    /**
     * 运行 MyBatis 代码创建程序
     * 
     * @param driver
     * @param dburl
     * @param username
     * @param password
     * @param packName
     * @param projectDir
     * @param tabName
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    private void creatAndRunMyBatis(String driver, String dburl, String username, String password, String packName, String projectSrcDir, String[] tabName)
        throws Exception
    {
        java.util.List<String> warnings = new ArrayList<>();
        Set<String> contexts = new HashSet<>();
        Set<String> fullyqualifiedTables = new HashSet<>();
        StringReader configStr = new StringReader(creatMybatisConig(driver, dburl, username, password, packName, projectSrcDir, tabName));
        InputSource inputSource = new InputSource(configStr);
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(inputSource);
        DefaultShellCallback shellCallback = new DefaultShellCallback(true);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, shellCallback, warnings);
        myBatisGenerator.generate(null, contexts, fullyqualifiedTables);
        for (String tableName : tabName)
        {
            String className;
            if (StringUtils.isEmpty(prefix))
            {
                className = StringUtil.camelCase(tableName, true);
            }
            else
            {
                className = StringUtil.camelCase(tableName.replaceAll("(?i)^" + prefix, ""), true);
            }
            Resources.init(driver, dburl, username, password, tableName, packName, projectDir, className, codeType);
            GenerateFactory factory = new GenerateFactory();
            factory.genJavaTemplate();
        }
    }
}
